

using Progress.Lang.*.
using OpenEdge.WebSpeed.*.

using OpenEdge.WebSpeed.Request from propath.
using OpenEdge.WebSpeed.Response from propath.
using OpenEdge.WebSpeed.WebObject from propath.

routine-level on error undo, throw.

class OpenEdge.WebSpeed.LegacyWebObject inherits WebObject: 
    
    define private variable CompileXCode   as character no-undo.
    	
    define private variable NoSaveRCode    as logical   no-undo.
    
    define private variable WebRunPath     as character no-undo.
    	
    define private variable CompileOnFly   as logical   no-undo.
    
    define private variable CheckTime      as logical   no-undo.
    	
    define private variable CompileOptions as character no-undo.
    
    constructor public LegacyWebObject(request as Request, response as response):
        super(request, response).
    end.
    
    method override public void BeginRequest().
    
        if this-object:Request:Container:DebuggingEnabled then 
        do:
            /* The following values are retrieved from the Configuration Manager. */
            this-object:CompileOptions		= this-object:Request:Container:AgentSettings:GetAgentSetting("Compile":U, "", "Options":U).
            this-object:CompileXCode			= this-object:Request:Container:AgentSettings:GetAgentSetting("Compile":U, "", "xcode":U).
            this-object:NoSaveRCode			= can-do(this-object:CompileOptions,"NoSave":U).
            this-object:Checktime        		= can-do(this-object:CompileOptions,"CheckTime":U).
            this-object:CompileOnFly   		= this-object:CompileOptions > "" and this-object:Request:Container:DevelopmentMode.
        end.
        this-object:WebRunPath 		= this-object:Request:Container:AgentSettings:GetAgentSetting("Path":U, "","WebRunPath":U).
    end.
    
    method override public void EndRequest().
    end.

    method override public void HandleRequest ():
        

        define variable cCompileExt    as character no-undo.
        define variable cCompilerMsg   as character no-undo.
        define variable cFileExt       as character no-undo.
        define variable cLog           as character no-undo. 
        define variable cRFile         as character no-undo.
        define variable cSearch        as character no-undo.
        define variable cSearchFile    as character no-undo.
        define variable cSessionPrefix as character no-undo.
        define variable dFile          as date      no-undo.
        define variable lCompiled      as logical   no-undo.
        define variable lRetVal        as logical   no-undo.
        define variable lRunOk         as logical   no-undo.
        define variable tFile          as integer   no-undo.
		
        /* Log all runs of workshop in Production */
        if not this-object:Request:Container:DevelopmentMode and request:AppProgram matches "workshop*":U then 
        do:
            cLog = substitute("WebSpeed Workshop (&1) was requested by &2",
                request:AppProgram, request:RemoteAddress) no-error.
        /*            dynamic-function ("logNote":U in web-utilities-hdl, "WARNING":U, cLog).*/
        end.
		   
        /* Make sure the file is in the PROPATH.  Make sure we can find rcode. */
        run adecomm/_rsearch.p (request:AppProgram, output cSearchFile).
		
        if cSearchFile = ? then
            /* If there is no rcode then just make sure the file is in the propath */
            run webutil/_relname.p (request:AppProgram, "MUST-BE-REL":U, output cSearchFile).  
        else 
        do:
            /* If we found rcode, then make sure the Rcode is in the propath */
            /* 
               This is not necessary if we found the rcode in a .pl file, since the .pl must
               have been added to the PROPATH, otherwise we wouldn't have found it in
               _rsearch.p to begin with. WE can't call _relname.p for .pl since it will always
               fail. 
            */
            if not cSearchFile matches ('*<<*>>':U) then 
                run webutil/_relname.p (input cSearchFile, "MUST-BE-REL":U, output cSearchFile).
        end.
		
        /* If the rcode or the file was not in the propath then error */
        if cSearchFile = ? then 
        do:
            /* If we found rcode but the file was not in the propath then reject it */
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "WARNING",                                  */
            /*                substitute ("&1 was requested by &2 but was not in the propath and was rejected. (Ref: &3)",*/
            /*                pcFilename, REMOTE_ADDR, HTTP_REFERER)) no-error.                                           */
            response:ShowErrorScreen(substitute ("Unable to find web object file '&1'", request:AppProgram)).
            return.
        end. /* Not found in the propath */
		
        /* If this is configured then perform the check, if its left blank, then 
           allow anything.  Check and see if there is a more restricted path for 
           running objects. */
        assign
            cSearchFile = search(cSearchFile).
		    
        if this-object:WebRunPath > "" and not can-do(this-object:WebRunPath,cSearchFile) then 
        do:
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "WARNING":U,                                   */
            /*                substitute ("&1 was requested by &2 but was not in the WebRunPath and was rejected. (Ref: &3)",*/
            /*                pcFilename, REMOTE_ADDR, HTTP_REFERER)) no-error.                                              */
             
            response:ShowErrorScreen( substitute ("Unable to find web object file '&1'", request:AppProgram)).  
            return.
        end. /* not found in the WebRunPath */
		
        /* Verify file extension is valid, i.e. .w, .r, .p, or .  */
        assign
            cSearch = if cSearchFile = ? then request:AppProgram
		              else if cSearchFile matches ('*<<*>>':U) then
		                entry(1,entry(3,cSearchFile,'<':U),'>':U)
		              else cSearchFile.
        run adecomm/_osfext.p (input cSearch, output cFileExt) no-error.
		    
        if cFileExt > "" and not can-do(".w,.p,.r,.":U, cFileExt) then 
            /* if the file cannot be run directly then look for rcode by the same file name */
            cSearchFile = search(substring(request:AppProgram, 1, r-index(request:AppProgram, ".":U),"CHARACTER":U) + "r":U).
		
        if this-object:CompileXCode > "" and can-do(".w,.p":U, cFileExt) then
            cSearchFile = search(substring(request:AppProgram, 1, r-index(request:AppProgram, ".":U),"CHARACTER":U) + "r":U).
		
        if this-object:CheckTime and cSearchFile > "" and not can-do(".r,.":U, cFileExt) then 
        do:
            file-info:file-name = cSearchFile.
            dFile               = file-info:file-mod-date.
            tFile               = file-info:file-mod-time.
            file-info:file-name = search(request:AppProgram).
            if   dFile < file-info:file-mod-date or 
                (dFile = file-info:file-mod-date and 
                tFile < file-info:file-mod-time) or 
                tFile = ?  then  
            do:
                /*                dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
                /*                    "Source Code has changed since compile.") no-error.         */
                os-delete VALUE(cSearchFile) NO-ERROR.
                cSearchFile = ?.
            end.
        end.
		
        /* If rcode is not available then see if we can compile the current file. */
        if this-object:CompileOnFly and cSearchFile = ? and not can-do(".r,.":U, cFileExt) then 
        do: 
            /* If we're allowed, try to find .html or .htm and try to compile it */
            cSearchFile = search(request:AppProgram).
            if cSearchFile > "" then 
            do:
                cCompilerMsg = webCompile(cSearchFile).  
		
                /* If the compile failed, then log the failed compile and return an error 
                   to the user. */
                if not cCompilerMsg begins "OK" then 
                do:
                    /*                    dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
                    /*                        cCompilerMsg + " ") no-error.                               */
                    /*                    dynamic-function ("logNote":U in web-utilities-hdl, "ERROR":U,  */
                    /*                        substitute ("&1 cannot be run as a web object (Ref: &2)"),  */
                    /*                        pcFileName, HTTP_REFERER) no-error.                         */
                    response:ShowErrorScreen( cCompilerMsg) .
                    return.
                end. 
                else 
                do:
                    /*                    dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
                    /*                        substitute ("Compiled &1 at run time",                      */
                    /*                        cSearchFile)) no-error.                                     */
                    lCompiled = true.
                end. /* compilermsg eq OK */
            end. /* could not find HTML file */
        end. /* Could not find the file at all and not in development mode */
		
        if cSearchfile = ? then 
        do: /* could not find html or rcode */
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "ERROR":U,*/
            /*                substitute("& could not be found (Ref: &2)",              */
            /*                pcFilename, HTTP_REFERER)) no-error.                      */
            response:ShowErrorScreen (substitute("Unable to find web object file '&1'", 
                request:AppProgram )) .
            return.
        end.  /* cannot find a file to run anywhere (or not in development )*/
		        
        /* Now check database connections prior to running/compiling. */
        /*        run dbCheck in web-utilities-hdl (input pcFilename, output lRetVal).*/
        if lRetVal eq false then 
        do:
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "ERROR":U,              */
            /*                substitute("&1 did not have the required databases connected (Ref: &2)",*/
            /*                pcFilename, HTTP_REFERER)) no-error.                                    */
            response:ShowErrorScreen(substitute("&1 cannot be run as a web object.", request:AppProgram)) .
            return.
        end.
		  
        /* Make a note about which program we are running. */
        cLog = "Running: " + request:AppProgram.
        /*        dynamic-function ("logNote":U in web-utilities-hdl, "RUN":U, cLog) no-error.*/
        error-status:error = false.
        compiler:error     = false.
		
        EXECUTE-BLOCK:   
        do on error  undo EXECUTE-BLOCK, leave EXECUTE-BLOCK  
            on endkey undo EXECUTE-BLOCK, leave EXECUTE-BLOCK
            on stop   undo EXECUTE-BLOCK, leave EXECUTE-BLOCK
            on quit                     , leave EXECUTE-BLOCK:
		
            run request:AppProgram no-error. 
        end.
		
        /* Did the code run okay?  Also trap for compiler error here, since some code 
           may run a program directly without running it through run-web-object */
        lRunOk = (not error-status:error and not compiler:error).  
        if not lRunOk then 
        do:
            if compiler:error = true then 
            do:
            /*                dynamic-function ("logNote":U in web-utilities-hdl, "Error":U,*/
            /*                    substitute ("Compile error in &1 at line &2.",            */
            /*                compiler:filename, compiler:error-row)) no-error.*/
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "Error":U,                                                */
            /*                substitute ("&1 tried to run but failed. Message: &2", pcFilename, error-status:get-message(1))) no-error.*/
            end.
            response:ShowErrorScreen( substitute ("Unable to run Web object '&1'", request:AppProgram)).
        end. /* IF...ERROR... */
		  
        cLog = substitute ("Finished: &1 : &2",request:AppProgram,
            string(lRunOk,"OK/ERROR")).
        /*    dynamic-function ("logNote":U in web-utilities-hdl, "RUN":U, cLog) no-error.*/
		
        /* If the requested file was compiled on the fly, and NoSave was specified 
           for r-code, then delete the temporary .r file. */
        if  this-object:NoSaveRCode and lCompiled then 
        do:
            /** check which file to delete */
            cSearchFile = substring(cSearchFile,1,r-index(cSearchFile, ".":U), "CHARACTER":U) + "r":U.
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
            /*                "NoSave Option -> Removing:" + cSearchFile) no-error.       */
            os-delete VALUE(cSearchFile) NO-ERROR.
        end.        
        
        
    end.
    
    
    /**
         Compiles a .html file to a .w then to a .r file
       
       */
    method private character WebCompile 
        ( cFile     as character) :
        define variable object-type as character no-undo.
        define variable cTempFile   as character no-undo.
        define variable cReturn     as character no-undo.
        define variable ix          as integer   no-undo.
  
        if cFile matches "*.html":U or cFile matches "*.htm":U then 
        do:
            run webutil/e4gl-gen.p (search(cFile), input-output object-type, 
                input-output cTempFile) no-error.
            if error-status:error then 
                return error-status:get-message(1).
        end.
        else 
            cTempFile = cFile.
  
        if this-object:CompileXCode > "" then 
        do:
            compile VALUE(cTempFile) save xcode this-object:CompileXCode no-error.
        /*            dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
        /*                "XCode Compile:" + cFile) no-error.                         */
        end.                                
        else 
        do: 
            /*            dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
            /*                "CompileOnFly:" + cFile) no-error.                          */
            compile VALUE(cTempFile) save no-error.
        end.
        if error-status:num-messages > 0 then 
        do:
            cReturn = "<h1>Compile Error: " + cFile + "</h1>":U.
            do ix = 1 to error-status:num-messages:
                cReturn = cReturn + "<br>":U + error-status:get-message(ix).
            end.
        /*            dynamic-function ("logNote":U in web-utilities-hdl, "COMPILE":U,*/
        /*                "ERROR:" + error-status:get-message(ix)) no-error.          */
        end.
        else 
        do: 
            cReturn = "OK":U.
            if cTempFile > "" and cTempFile <> cFile then
                os-delete VALUE(cTempFile) NO-ERROR.
        end.
        return cReturn.

    end .    
    
end class.